package org.ourgrid.broker.business.requester;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.ourgrid.broker.BrokerConstants;
import org.ourgrid.broker.business.dao.BrokerDAOFactory;
import org.ourgrid.broker.business.dao.PeerDAO;
import org.ourgrid.broker.business.dao.PeerEntry;
import org.ourgrid.broker.business.messages.BrokerControlMessages;
import org.ourgrid.broker.business.scheduler.SchedulerIF;
import org.ourgrid.broker.business.schedulerdata.SchedulerData;
import org.ourgrid.broker.business.schedulerdata.executor.control.SchedulerDataExecutorControl;
import org.ourgrid.broker.request.SetPeersRequestTO;
import org.ourgrid.common.interfaces.LocalWorkerProvider;
import org.ourgrid.common.internal.IResponseTO;
import org.ourgrid.common.internal.RequesterIF;
import org.ourgrid.common.internal.response.LocalWorkerProviderReleaseResponseTO;
import org.ourgrid.common.internal.response.LoggerResponseTO;
import org.ourgrid.common.internal.response.OperationSucceedResponseTO;
import org.ourgrid.common.internal.response.RegisterInterestResponseTO;

public class SetPeersRequester implements RequesterIF<SetPeersRequestTO> {

	public List<IResponseTO> execute(SetPeersRequestTO request) {
		List<IResponseTO> responses = new ArrayList<IResponseTO>();
		
		String senderPubKey = request.getSenderPublicKey();
		if (!request.isThisMyPublicKey()) {
			responses.add(new LoggerResponseTO(BrokerControlMessages.getUnknownSenderControllingBrokerMessage(senderPubKey), LoggerResponseTO.WARN));
			
			return responses;
		}
		
		if (!request.canComponentBeUsed()) {
			responses.add(new LoggerResponseTO(BrokerControlMessages.getComponentNotStartedMessage(), LoggerResponseTO.ERROR));
			
			return responses;
		}
		
		PeerDAO peerDAO = BrokerDAOFactory.getInstance().getPeerDAO();
		Collection<String> oldPeersAddresses = peerDAO.getPeersAddresses();
		
		List<String> peersAddresses = request.getPeersAddress();
		
		String[] newPeerServiceID = new String[peersAddresses.size()];
		int i = 0;

		
		for (String peerAddress : peersAddresses) {
			PeerEntry peerEntry = peerDAO.getPeerEntry(peerAddress);
			
			newPeerServiceID[i] = peerAddress;
			i++;
			
			if (peerEntry == null) {
				RegisterInterestResponseTO to = new RegisterInterestResponseTO();
				to.setMonitorableAddress(peerAddress);
				to.setMonitorableType(LocalWorkerProvider.class);
				to.setMonitorName(BrokerConstants.LOCAL_WORKER_PROVIDER_CLIENT);
				
				responses.add(to);
			} else {
				oldPeersAddresses.remove(peerAddress);
			}
		}
		
		//unregister the remaining peers
		for (String peerAddress : oldPeersAddresses) {
			PeerEntry peerEntry = peerDAO.getPeerEntry(peerAddress);
			
			if (peerEntry.isLogged()) {
				finishRequests(peerAddress, responses);
			}
			
			LocalWorkerProviderReleaseResponseTO to = new LocalWorkerProviderReleaseResponseTO();
			to.setStubAddress(peerAddress);
			
			responses.add(to);
		}
		
		peerDAO.setPeers(request.getPeers());
		
		List<SchedulerData> outputCommands = new ArrayList<SchedulerData>();
		
		for(SchedulerIF scheduler: BrokerDAOFactory.getInstance().getJobDAO().getSchedulers()) {
			List<SchedulerData> cjData = scheduler.setPeers(newPeerServiceID);
			if (cjData != null) {
				outputCommands.addAll(cjData);
			}	
		}
		
		responses.addAll(SchedulerDataExecutorControl.getInstance().execute(outputCommands));
		
		OperationSucceedResponseTO to = new OperationSucceedResponseTO();
		to.setClientAddress(request.getBrokerControlClientAddress());
		
		responses.add(to);
		
		return responses;
	}
	
	private void finishRequests(String peerServiceID, List<IResponseTO> responses) {
		
		List<SchedulerData> outputCommands = new ArrayList<SchedulerData>();
		
		for(SchedulerIF scheduler: BrokerDAOFactory.getInstance().getJobDAO().getSchedulers()) {
			List<SchedulerData> cjData = scheduler.finishPeerRequests(peerServiceID);
			if (cjData != null) {
				outputCommands.addAll(cjData);
			}	
		}
		
		responses.addAll(SchedulerDataExecutorControl.getInstance().execute(outputCommands));
	}
}
